/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： App_Protocol_BluePoint_CAN.c
** 模块名称： 蓝点CAN协议模块
** 版 本 号： V1.0
** 作    者： 蒲磊
**
** 修改记录： 版本     修改人      时间         修改内容
**
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include "App_Protocol_BluePoint_CAN.h"
#include "stdlib.h"
#include "App_MainTask.h"
/******************************************************************************
* 宏定义
******************************************************************************/

/******************************************************************************
* 类型定义
******************************************************************************/

/******************************************************************************
* 函数声明
******************************************************************************/
static void vBP_CAN_ReceivePublishMessage(strBP_CAN *pBPCanMsg,strBikeInfo *pBikeInfo);
//static void vBP_CAN_ReceiveBroadcastMessage(strBP_CAN   *pBPCanMsg,strBikeInfo *pBikeInfo);
static void vBP_CAN_ReceiveDisplayMessage(strBP_CAN *pBPCanMsg,strBikeInfo *pBikeInfo);
static void vBP_CAN_ReceivePublishCommonMessage(strBP_CAN   *pBPCanMsg,strBikeInfo *pBikeInfo);
static void vBP_CAN_Transmit(strBP_CAN *pCanMessage);
static void vBP_CAN_Send_Display_Msg6300(enuNodeID DstNodeId);
static void vBP_CAN_Send_Display_Msg6301(enuNodeID DstNodeId);
static void vBP_CAN_Send_Display_Msg6302(enuNodeID DstNodeId);
static void vBP_CAN_Send_Display_Msg6303(enuNodeID DstNodeId);
static void vBP_CAN_Send_Display_Msg3000(enuNodeID DstNodeId);
static void vBP_CAN_Send_Display_Msg6400(enuNodeID DstNodeId);
static void vBP_CAN_ReceiveCalibrationMessage(strBP_CAN *pBPCanMsg,strBikeInfo *pBikeInfo);
//static void vPROTOCOL_Get_LongDataRead(strBP_CAN   *pBPCanMsg,strBikeInfo *pBikeInfo);
void vBP_CAN_Send_OK_Ack(enuNodeID SourceID,enuNodeID TargetID,uint8_t Index,uint8_t SubIndex,uint8_t Datalen,uint8_t * pData);
void vBP_CAN_Send_Error_Ack(enuNodeID SourceID,enuNodeID TargetID,uint8_t Index,uint8_t SubIndex,uint8_t Datalen,uint8_t * pData);
/******************************************************************************
* 全局变量定义
******************************************************************************/
strBikeInfo     gxBikeInfo = {0};         /*车辆数据*/
static uint32_t lulCommunicationCnt = 0;
static uint8_t  gucTripCleared = 0;
static uint32_t lulCommunicationCnt_mcu = 0;
static uint32_t lulCommunicationCnt_bat = 0;
static uint32_t lulCommunicationCnt_hub = 0;

const static char *Dis_H_Version  = "V1.0";      /*硬件版本号*/
const static char *Dis_S_Version  = "V2.0.0";    /*软件版本号*/
const static char *Dis_M_Version  = "KD686";     /*型号*/
/*****************************************************************************
* 函数实现
******************************************************************************/

/******************************************************************************
** 功  能：八方CAN协议初始化函数
** 参  数：无
** 返回值：无
** 备  注：用于初始化CAN协议模块的相关变量，同时创建收发队列。
**        该函数需要在BP_CAN_CanToBF函数调用之前初始化
******************************************************************************/
void vPROTOCOL_Init(void)
{
    muilt_cyc_fifo_error_code_t    lxState;
    MCF_ApplyFifo(gxCAN_RxQueue_Len,gxCAN_RxQueue,&lxState);     /*初始化接收队列*/
    MCF_ApplyFifo(gxCAN_TxQueue_Len,gxCAN_TxQueue,&lxState);     /*初始化发送队列*/
    gxBikeInfo.Display.ClearTrip = 1;
    gxBikeInfo.MCU.RemainCapacity = -1;
}

/******************************************************************************
** 功  能：八方CAN发送函数
** 参  数：pCanMessage-指向要发送的数据结构体
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_Transmit(strBP_CAN *pCanMessage)
{
    uint8_t n;
    can_tx_message_type    lxCanTxMessage;


    lxCanTxMessage.id_type = CAN_ID_EXTENDED;       /*扩展帧*/
    /*扩展帧ID*/
    lxCanTxMessage.extended_id = ((uint32_t)pCanMessage->ID_Src << 24) | ((uint32_t)pCanMessage->ID_Dst << 19) |
                                 ((uint32_t)pCanMessage->Command << 16) | ((uint32_t)pCanMessage->Index << 8) | (pCanMessage->SubIndex);
    lxCanTxMessage.frame_type = CAN_TFT_DATA;         /*数据帧*/
    lxCanTxMessage.dlc = pCanMessage->DLC;      /*数据长度*/
    for(n = 0; n < 8; n++)
    {
        lxCanTxMessage.data[n] = pCanMessage->Data[n];
    }

    /*调用发送函数进行发送*/
    can_message_transmit(CAN1,&lxCanTxMessage);
}

/******************************************************************************
** 功  能：将接收到的Can帧解析为蓝点的Can数据结构
** 参  数：pCanMessage-接收到的Can数据结构体指针
** 返回值：无
** 备  注：该函数是整个Can协议模块的入口函数。当CAN总线接收一帧Can数据后，调用该函数，
**        将Can消息帧转换为蓝点的CAN数据格式，并且放入接收队列
******************************************************************************/
void vPROTOCOL_CanMsgToUserMsg(can_rx_message_type *pCanMessage)
{
    strBP_CAN lxBPCanMessage;
    muilt_cyc_fifo_error_code_t lxState;
    unsigned char n;

    lxBPCanMessage.ID_Src   = (enuNodeID)((pCanMessage->extended_id) >> 24);
    lxBPCanMessage.ID_Dst   = (enuNodeID)(((pCanMessage->extended_id) & 0x00F80000) >> 19);
    lxBPCanMessage.Command  = (enuCommand)(((pCanMessage->extended_id) & 0x00070000) >> 16);
    lxBPCanMessage.Index    = ((pCanMessage->extended_id) & 0x0000FF00) >> 8;
    lxBPCanMessage.SubIndex = ((pCanMessage->extended_id) & 0x000000FF);
    lxBPCanMessage.DLC      = pCanMessage->dlc;
    for(n = 0; n < pCanMessage->dlc; n++)
    {
        lxBPCanMessage.Data[n] = pCanMessage->data[n];
    }

    /*将转换后的Can数据放入FIFO队列*/
    MCF_WriteDataInFifo(gxCAN_RxQueue,(uint8_t *)&lxBPCanMessage,sizeof(strBP_CAN),&lxState);
}

/******************************************************************************
** 功  能：八方CAN轮询主函数
** 参  数：无
** 返回值：无
** 备  注：该函数判断接收缓冲区是否有数据，如有，则取出并处理，同时判断发送缓冲区是否有
**        数据，如果有，取出并发送。
**        该函数需要循环调用，调用周期应小于最小接收周期和最小发送周期
******************************************************************************/
void vPROTOCOL_Loop(void)
{
    static uint32_t lulTicks = 0;

    muilt_cyc_fifo_error_code_t lxState;
    uint16_t lxFifoCanReadLen;
    uint16_t lxActualReadLen;

    strBP_CAN       lxBP_CAN_RxMessage;
    strBP_CAN       lxBP_CAN_TxMessage;

    /*100ms发送一次的帧*/
    if(lulTicks % (100 / CAN_LOOP_CYCLE) == 0)
    {
        /*处于正常模式下，发送仪表主数据帧，处于密码设置界面时，不发送该帧*/
        if(gxBikeInfo.Display.IsInPassword == 0)
        {
            vBP_CAN_Send_Display_Msg6300(Node_Broadcast);
        }

    }

    /*100ms发送一次的帧--花鼓锁锁控*/
    if(lulTicks % (100 / CAN_LOOP_CYCLE) == 1)
    {
        vBP_CAN_Send_Display_Msg6400(Node_Broadcast);
    }

    /*1000ms发送一次的帧*/
    if(lulTicks % (1000 / CAN_LOOP_CYCLE) == 0)
    {
        vBP_CAN_Send_Display_Msg6303(Node_Broadcast);     /*自动关机时间*/
    }
    /*10S一次的心跳帧*/
    if(lulTicks % (10000 / CAN_LOOP_CYCLE) == 0)
    {
        vBP_CAN_Send_Display_Msg3000(Node_Broadcast);     /*仪表心跳帧*/
    }

    lulTicks++;
    lulCommunicationCnt++;
    lulCommunicationCnt_mcu++;
    lulCommunicationCnt_bat++;
    lulCommunicationCnt_hub++;

    /*10S之内，通信超时变量未复位，报30错误,并清其他错误*/
    if(lulCommunicationCnt > (10000 / CAN_LOOP_CYCLE))
    {
        gxBikeInfo.ErrCode = 0x30;
        gxBikeInfo.MCU.ErrCode = 0;
        gxBikeInfo.Battery.ErrCode = 0;
        gxBikeInfo.HubLock.ErrCode = 0;
    }
    else
    {
        if(gxBikeInfo.ErrCode == 0x30)
        {
            gxBikeInfo.ErrCode = 0;
        }
    }

    if(lulCommunicationCnt_mcu > (10000 / CAN_LOOP_CYCLE))
    {
        gxBikeInfo.MCU.ErrCode = 0;
    }
    if(lulCommunicationCnt_bat > (10000 / CAN_LOOP_CYCLE))
    {
        gxBikeInfo.Battery.ErrCode = 0;
    }
    if(lulCommunicationCnt_hub > (10000 / CAN_LOOP_CYCLE))
    {
        gxBikeInfo.HubLock.ErrCode = 0;
    }

    /*判断接收队列是否非空*/
    MCF_GetCanReadLen(gxCAN_RxQueue,&lxFifoCanReadLen,&lxState);
    if(lxState == kMultiCycFiFo_Error_NONE && lxFifoCanReadLen > 0)
    {
        MCF_ReadDataFromFifo(gxCAN_RxQueue,sizeof(strBP_CAN),(uint8_t *)&lxBP_CAN_RxMessage,&lxActualReadLen,&lxState);/*从队列中取出一组CAN数据*/
        if(lxActualReadLen == sizeof(strBP_CAN) && lxState == kMultiCycFiFo_Error_NONE)
        {
            lulCommunicationCnt = 0;        /*复位通信超时计数*/
            /*判断目的节点*/
            switch(lxBP_CAN_RxMessage.ID_Dst)
            {
            case Node_Broadcast:          /*发布的消息，所有节点均接收*/
            {
                vBP_CAN_ReceivePublishMessage(&lxBP_CAN_RxMessage,&gxBikeInfo);
                break;
            }
            case Node_PC:               /*校准消息*/
            {
                vBP_CAN_ReceiveCalibrationMessage(&lxBP_CAN_RxMessage,&gxBikeInfo);
                break;
            }
            case Node_LCD:              /*发给仪表的消息*/
            {
                vBP_CAN_ReceiveDisplayMessage(&lxBP_CAN_RxMessage,&gxBikeInfo);
                break;
            }
            default:
                break;              /*其它消息不接收*/
            }
//            switch(lxBP_CAN_RxMessage.ID_Src)
//            {
//                case Node_MCU:          /*发布的消息，所有节点均接收*/
//                {
//                    lulCommunicationCnt_mcu = 0;
//                    break;
//                }
//                case Node_LCD:              /*发给仪表的消息*/
//                {
//                    lulCommunicationCnt_bat = 0;
//                    break;
//                }
//                default:break;              /*其它消息不接收*/
//            }
        }
    }

    vBP_CAN_Send_Get_All_Version();/*读取所有系统的版本号*/

    /*判断发送缓冲区是否有数据需要发送*/
    MCF_GetCanReadLen(gxCAN_TxQueue,&lxFifoCanReadLen,&lxState);
    if(lxState == kMultiCycFiFo_Error_NONE && lxFifoCanReadLen > 0)
    {
        MCF_ReadDataFromFifo(gxCAN_TxQueue,sizeof(strBP_CAN),(uint8_t *)&lxBP_CAN_TxMessage,&lxActualReadLen,&lxState);/*从队列中取出一组CAN数据*/
        if(lxActualReadLen == sizeof(strBP_CAN) && lxState == kMultiCycFiFo_Error_NONE)
        {
            vBP_CAN_Transmit(&lxBP_CAN_TxMessage);                          /*将八方CAN数据转换为实际的CAN帧，并发送*/
        }
    }
}

/******************************************************************************
** 功  能：接收处理目标节点为发布节点的消息
** 参  数：pBPCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_ReceivePublishMessage(strBP_CAN *pBPCanMsg,strBikeInfo *pBikeInfo)
{
    uint8_t i;
    switch(pBPCanMsg->Command)
    {
    case Command_State_Code:    /*状态码命令，用于告警信息*/
    {
        if(pBPCanMsg->SubIndex == 0x00 || pBPCanMsg->SubIndex == 0x01)
        {
            if(pBPCanMsg->Index == 0x03)
            {
                lulCommunicationCnt_hub = 0;
                pBikeInfo->HubLock.ErrCode = pBPCanMsg->Data[0] + 0x60;     /*花鼓锁错误代码*/
                pBikeInfo->HubLock.State = pBPCanMsg->Data[1];              /**/
            }
            else if(pBPCanMsg->Index == 0x12)
            {
                lulCommunicationCnt_mcu = 0;
                pBikeInfo->MCU.ErrCode = pBPCanMsg->Data[0];     /*控制器错误代码*/
            }
            else if(pBPCanMsg->Index == 0x14)                       /*电池系统错误代码*/
            {
                lulCommunicationCnt_bat = 0;
                for(i =0; i<7; i++)
                {
                    if((pBPCanMsg->Data[0] >> i & 0x01) > 0)
                    {
                        pBikeInfo->Battery.ErrCode = 0x40 + i;        /*控制器错误代码*/
                        break;
                    }
                }
            }
            if(pBikeInfo->ErrCode != 0)
            {
                vSave_ErrorCode(pBikeInfo->ErrCode);        /*存储本次的故障码*/
            }
        }
        else
        {

        }
        break;
    }
    case Command_Write:         /*通用公共信息，索引值0x3x开头的信息*/
    {
        vBP_CAN_ReceivePublishCommonMessage(pBPCanMsg,pBikeInfo);
        break;
    }
    default:
    {
        break;
    }
    }
}
/******************************************************************************
** 功  能：接收处理目标节点为仪表节点的消息
** 参  数：pBPCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_ReceiveCalibrationMessage(strBP_CAN *pBPCanMsg,strBikeInfo *pBikeInfo)
{
    uint16_t MsgIndex;

    uint8_t  lucTempData[8];
    uint16_t lusPhotoDiode_ADC;
    uint16_t lusVoltage_ADC;

    MsgIndex = (uint16_t)pBPCanMsg->Index << 8 | pBPCanMsg->SubIndex;

    switch(MsgIndex)
    {
    case 0x016E:/*校准光感*/
    {
        lusPhotoDiode_ADC = vPhotoDiode_Calibration();

        lucTempData[0] = lusPhotoDiode_ADC >> 8;
        lucTempData[1] = (uint8_t)lusPhotoDiode_ADC;

        vBP_CAN_Send_Msg(Node_PC,Node_Broadcast,Command_Write,0x01,0x6E,2,lucTempData);
        break;
    }
    case 0x025D:/*校准电压*/
    {
        lusVoltage_ADC = vVoltage_Calibration();

        lucTempData[0] = lusVoltage_ADC >> 8;
        lucTempData[1] = (uint8_t)lusVoltage_ADC;

        vBP_CAN_Send_Msg(Node_PC,Node_Broadcast,Command_Write,0x02,0x5D,2,lucTempData);
        break;
    }
    case 0x0371:/*校准时间*/
    {
        vDateTime_Calibration(pBPCanMsg->Data[3],pBPCanMsg->Data[4],pBPCanMsg->Data[5],pBPCanMsg->Data[0],pBPCanMsg->Data[1],pBPCanMsg->Data[2]);

        lucTempData[0] = 1234 >> 8;
        lucTempData[1] = (uint8_t)1234;

        vBP_CAN_Send_Msg(Node_PC,Node_Broadcast,Command_Write,0x03,0x71,2,lucTempData);
        break;
    }
    case 0x048E:/*清ODO*/
    {
        vClear_ODO();

        lucTempData[0] = 5678 >> 8;
        lucTempData[1] = (uint8_t)5678;

        vBP_CAN_Send_Msg(Node_PC,Node_Broadcast,Command_Write,0x04,0x8E,2,lucTempData);
        break;
    }
    }
}
/******************************************************************************
** 功  能：接收处理目标节点为仪表节点的消息
** 参  数：pBPCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_ReceiveDisplayMessage(strBP_CAN *pBPCanMsg,strBikeInfo *pBikeInfo)
{
    uint16_t MsgIndex;
    uint32_t lulBesset_Trip,lulBesset_Odo,lulBesset_ServiceMileage;
    uint8_t lucHour,lucMin,lucSecond;
    uint8_t n;
    uint8_t lucVersion[8] = {0};

    MsgIndex = (uint16_t)pBPCanMsg->Index << 8 | pBPCanMsg->SubIndex;

    switch(MsgIndex)
    {
    case 0x3201:    /*速度、电流、电压(此处是为了适配八方CAN的工装增加的，实际控制器发送的，在公共信息里面)*/
    {
        pBikeInfo->MCU.Speed   = ((uint16_t)pBPCanMsg->Data[1] << 8) | pBPCanMsg->Data[0];      /*速度，精度0.01km/h*/
        //pBikeInfo->MCU.Current = ((uint16_t)pBPCanMsg->Data[3] << 8) | pBPCanMsg->Data[2];      /*电流，精度0.01A，无符号*/
        //pBikeInfo->MCU.Voltage = ((uint16_t)pBPCanMsg->Data[5] << 8) | pBPCanMsg->Data[4];      /*电压，精度0.01V*/
        break;
    }
    case 0x6201:/*设置仪表总里程*/
    {
        if(pBPCanMsg->ID_Src == Node_Besst && pBPCanMsg->Command == Command_Write)
        {
            lulBesset_Odo = (uint32_t)pBPCanMsg->Data[2] << 16 | (uint32_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];
            vSet_And_Save_ODO(lulBesset_Odo);
            vBP_CAN_Send_OK_Ack(pBPCanMsg->ID_Dst,pBPCanMsg->ID_Src,pBPCanMsg->Index,pBPCanMsg->SubIndex,0,NULL);
        }
        break;
    }
    case 0x6202:/*设置仪表时间*/
    {
        if(pBPCanMsg->ID_Src == Node_Besst && pBPCanMsg->Command == Command_Write)
        {
            lucHour   = pBPCanMsg->Data[0];
            lucMin    = pBPCanMsg->Data[1];
            lucSecond = pBPCanMsg->Data[2];
            vSet_Clock(lucHour,lucMin,lucSecond);
            vBP_CAN_Send_OK_Ack(pBPCanMsg->ID_Dst,pBPCanMsg->ID_Src,pBPCanMsg->Index,pBPCanMsg->SubIndex,0,NULL);
        }

        break;
    }
    case 0x6203:/*仪表单里程Trip设置*/
    {
        if(pBPCanMsg->ID_Src == Node_Besst && pBPCanMsg->Command == Command_Write)
        {
            lulBesset_Trip = (uint32_t)pBPCanMsg->Data[2] << 16 | (uint32_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];
            vSet_And_Save_TRIP(lulBesset_Trip);
            vBP_CAN_Send_OK_Ack(pBPCanMsg->ID_Dst,pBPCanMsg->ID_Src,pBPCanMsg->Index,pBPCanMsg->SubIndex,0,NULL);
        }
        break;
    }
    case 0x6301:/*仪表ODO里程，单里程，最大速度*/
    {
        if(pBPCanMsg->Command == Command_Read)
        {
            vBP_CAN_Send_Display_Msg6301(pBPCanMsg->ID_Src);
        }
        break;
    }
    case 0x6302:/*设置仪表维护里程*/
    {
        if(pBPCanMsg->ID_Src == Node_Besst && pBPCanMsg->Command == Command_Write)
        {
            lulBesset_ServiceMileage = (uint32_t)pBPCanMsg->Data[4] << 16 | (uint32_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];
            vSet_And_Save_ServiceMileage(lulBesset_ServiceMileage);
            vBP_CAN_Send_OK_Ack(pBPCanMsg->ID_Dst,pBPCanMsg->ID_Src,pBPCanMsg->Index,pBPCanMsg->SubIndex,0,NULL);
        }
        else if(pBPCanMsg->Command == Command_Read)
        {
            vBP_CAN_Send_Display_Msg6302(pBPCanMsg->ID_Src);
        }

        break;
    }
    case 0x6400:/*电池设计信息，串数和并数*/
    {
        pBikeInfo->Battery.SeriesNum   = pBPCanMsg->Data[0];  /*电池串数*/
        pBikeInfo->Battery.ParallelNum = pBPCanMsg->Data[1];  /*电池并数*/
        break;
    }
    case 0x6401:/*电池循环信息，循环次数和充电未充电时间*/
    {
        pBikeInfo->Battery.CycleTimes       = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];    /*循环次数*/
        pBikeInfo->Battery.MaxUnchargeTime  = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];    /*最大未充电时间*/
        pBikeInfo->Battery.LastUnchargeTime = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];    /*最近未充电时间*/
        break;
    }
    case 0x6402:/*单芯电压信息，电芯1-4*/
    {
        pBikeInfo->Battery.CellVoltage[0] = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];/*电芯1电压，mv*/
        pBikeInfo->Battery.CellVoltage[1] = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];/*电芯2电压，mv*/
        pBikeInfo->Battery.CellVoltage[2] = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];/*电芯3电压，mv*/
        pBikeInfo->Battery.CellVoltage[3] = (uint16_t)pBPCanMsg->Data[7] << 8 | pBPCanMsg->Data[6];/*电芯4电压，mv*/
        break;
    }
    case 0x6403:/*单芯电压信息，电芯5-8*/
    {
        pBikeInfo->Battery.CellVoltage[4] = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];/*电芯4电压，mv*/
        pBikeInfo->Battery.CellVoltage[5] = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];/*电芯5电压，mv*/
        pBikeInfo->Battery.CellVoltage[6] = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];/*电芯6电压，mv*/
        pBikeInfo->Battery.CellVoltage[7] = (uint16_t)pBPCanMsg->Data[7] << 8 | pBPCanMsg->Data[6];/*电芯7电压，mv*/
        break;
    }
    case 0x6404:/*单芯电压信息，电芯9-12*/
    {
        pBikeInfo->Battery.CellVoltage[8]  = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];/*电芯8电压，mv*/
        pBikeInfo->Battery.CellVoltage[9]  = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];/*电芯9电压，mv*/
        pBikeInfo->Battery.CellVoltage[10] = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];/*电芯10电压，mv*/
        pBikeInfo->Battery.CellVoltage[11] = (uint16_t)pBPCanMsg->Data[7] << 8 | pBPCanMsg->Data[6];/*电芯11电压，mv*/
        break;
    }
    case 0x6405:/*单芯电压信息，电芯13-16*/
    {
        pBikeInfo->Battery.CellVoltage[12] = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];/*电芯12电压，mv*/
        pBikeInfo->Battery.CellVoltage[13] = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];/*电芯13电压，mv*/
        pBikeInfo->Battery.CellVoltage[14] = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];/*电芯14电压，mv*/
        pBikeInfo->Battery.CellVoltage[15] = (uint16_t)pBPCanMsg->Data[7] << 8 | pBPCanMsg->Data[6];/*电芯15电压，mv*/
        break;
    }
    case 0x6406:/*单芯电压信息，电芯17-20*/
    {
        pBikeInfo->Battery.CellVoltage[16] = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];/*电芯16电压，mv*/
        pBikeInfo->Battery.CellVoltage[17] = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];/*电芯17电压，mv*/
        pBikeInfo->Battery.CellVoltage[18] = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];/*电芯18电压，mv*/
        pBikeInfo->Battery.CellVoltage[19] = (uint16_t)pBPCanMsg->Data[7] << 8 | pBPCanMsg->Data[6];/*电芯19电压，mv*/
        break;
    }
    case 0x6407:/*单芯电压信息，电芯21-24*/
    {
        pBikeInfo->Battery.CellVoltage[20] = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];/*电芯20电压，mv*/
        pBikeInfo->Battery.CellVoltage[21] = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];/*电芯21电压，mv*/
        pBikeInfo->Battery.CellVoltage[22] = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];/*电芯22电压，mv*/
        pBikeInfo->Battery.CellVoltage[23] = (uint16_t)pBPCanMsg->Data[7] << 8 | pBPCanMsg->Data[6];/*电芯23电压，mv*/
        break;
    }
    case 0x6408:/*单芯电压信息，电芯25-28*/
    {
        pBikeInfo->Battery.CellVoltage[24] = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];/*电芯24电压，mv*/
        pBikeInfo->Battery.CellVoltage[25] = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];/*电芯25电压，mv*/
        pBikeInfo->Battery.CellVoltage[26] = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];/*电芯26电压，mv*/
        pBikeInfo->Battery.CellVoltage[27] = (uint16_t)pBPCanMsg->Data[7] << 8 | pBPCanMsg->Data[6];/*电芯27电压，mv*/
        break;
    }
    case 0x6409:/*单芯电压信息，电芯29-32*/
    {
        pBikeInfo->Battery.CellVoltage[28] = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];/*电芯28电压，mv*/
        pBikeInfo->Battery.CellVoltage[29] = (uint16_t)pBPCanMsg->Data[3] << 8 | pBPCanMsg->Data[2];/*电芯29电压，mv*/
        pBikeInfo->Battery.CellVoltage[30] = (uint16_t)pBPCanMsg->Data[5] << 8 | pBPCanMsg->Data[4];/*电芯30电压，mv*/
        pBikeInfo->Battery.CellVoltage[31] = (uint16_t)pBPCanMsg->Data[7] << 8 | pBPCanMsg->Data[6];/*电芯31电压，mv*/
        break;
    }
    case 0x6000: /*硬件号*/
    {
        if(pBPCanMsg->Command == Command_Ack_Ok)
        {
            switch(pBPCanMsg->ID_Src)
            {
            case Node_MCU:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->MCU.HardwareVersion[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
                break;
            }
            case Node_Battery:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->Battery.HardwareVersion[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
                break;
            }
            case Node_HubLock:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->HubLock.HardwareVersion[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
                break;
            }
            default :
                break;
            }
        }
        else if(pBPCanMsg->Command == Command_Read)
        {
            for(n=0; n<8; n++)
            {
                if(Dis_H_Version[n])
                {
                    lucVersion[n] = Dis_H_Version[n] ;
                }
                else
                {
                    lucVersion[n] = 0;
                }

            }
            vBP_CAN_Send_Msg(pBPCanMsg->ID_Dst, pBPCanMsg->ID_Src,Command_Ack_Ok,0x60,0x00,8,lucVersion);
        }
        break;
    }
    case 0x6001: /*软件号*/
    {
        if(pBPCanMsg->Command == Command_Ack_Ok)
        {
            switch(pBPCanMsg->ID_Src)
            {
            case Node_MCU:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->MCU.SoftwareVersion[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
            }
            case Node_Battery:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->Battery.SoftwareVersion[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
            }
            case Node_HubLock:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->HubLock.SoftwareVersion[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
            }
            default :
                break;
            }
        }
        else if(pBPCanMsg->Command == Command_Read)
        {
            for(n=0; n<8; n++)
            {
                if(Dis_S_Version[n])
                {
                    lucVersion[n] = Dis_S_Version[n] ;
                }
                else
                {
                    lucVersion[n] = 0;
                }

            }
            vBP_CAN_Send_Msg(pBPCanMsg->ID_Dst,pBPCanMsg->ID_Src,Command_Ack_Ok,0x60,0x01,8,lucVersion);
        }
        break;
    }
    case 0x6002: /*型号*/
    {
        if(pBPCanMsg->Command == Command_Ack_Ok)
        {
            switch(pBPCanMsg->ID_Src)
            {
            case Node_MCU:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->MCU.Model[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
            }
            case Node_Battery:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->Battery.Model[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
            }
            case Node_HubLock:
            {
                for(n = 0; n < 8; n++)
                {
                    pBikeInfo->HubLock.Model[n] = pBPCanMsg->Data[n];	/*将版本号信息拷贝到对应数组*/
                }
            }
            default :
                break;
            }
        }
        else if(pBPCanMsg->Command == Command_Read)
        {
            for(n=0; n<8; n++)
            {
                if(Dis_M_Version[n])
                {
                    lucVersion[n] = Dis_M_Version[n] ;
                }
                else
                {
                    lucVersion[n] = 0;
                }

            }
            vBP_CAN_Send_Msg(pBPCanMsg->ID_Dst,pBPCanMsg->ID_Src,Command_Ack_Ok,0x60,0x02,8,lucVersion);
        }
        break;
    }
    default:/*索引值为其它的消息，判断是否是长数据，是的话按照长数据进行收发*/
    {
        //vPROTOCOL_Get_LongDataRead(pBPCanMsg,pBikeInfo);
        break;
    }
    }
}




/******************************************************************************
** 功  能：解析发布的公共信息数据
** 参  数：pBPCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
void vBP_CAN_ReceivePublishCommonMessage(strBP_CAN  *pBPCanMsg,strBikeInfo *pBikeInfo)
{
    uint16_t MsgIndex;

    MsgIndex = (uint16_t)pBPCanMsg->Index << 8 | pBPCanMsg->SubIndex;

    switch(MsgIndex)
    {
    case 0x3200:      /*控制器信息*/
    {
        if(gxBikeInfo.MCU.ErrCode != 0x06)
        {
            pBikeInfo->MCU.RemainCapacity = pBPCanMsg->Data[0];     /*剩余电量*/
        }
        else
        {
            pBikeInfo->MCU.RemainCapacity = 0;     /*剩余电量*/
        }
        pBikeInfo->MCU.Trip           = ((uint16_t)pBPCanMsg->Data[2] << 8) | pBPCanMsg->Data[1];   /*单里程，精度0.01km*/
        pBikeInfo->MCU.Cadence        = pBPCanMsg->Data[3];     /*踏频*/
        pBikeInfo->MCU.Range          = ((uint16_t)pBPCanMsg->Data[7] << 8) | pBPCanMsg->Data[6];   /*剩余里程，精度0.01km*/
        if(gucTripCleared == 0 && pBikeInfo->MCU.Trip == 0)
        {
            gucTripCleared = 1;
        }
        break;
    }
    case 0x3201:    /*速度、电流、电压*/
    {
        pBikeInfo->MCU.Speed   = ((uint16_t)pBPCanMsg->Data[1] << 8) | pBPCanMsg->Data[0];      /*速度，精度0.01km/h*/
        pBikeInfo->MCU.Current = ((uint16_t)pBPCanMsg->Data[3] << 8) | pBPCanMsg->Data[2];      /*电流，精度0.01A，无符号*/
        pBikeInfo->MCU.Voltage = ((uint16_t)pBPCanMsg->Data[5] << 8) | pBPCanMsg->Data[4];      /*电压，精度0.01V*/
        break;
    }
    case 0x3202:    /*是否启动助推*/
    {
        pBikeInfo->MCU.PushState = pBPCanMsg->Data[0];
        break;
    }
    case 0x3203:
    {
        pBikeInfo->MCU.SpeedLimit = ((uint16_t)pBPCanMsg->Data[1] << 8) | pBPCanMsg->Data[0];   /*限速值，精度0.01km/h*/
        pBikeInfo->MCU.WheelSize  = (((uint16_t)pBPCanMsg->Data[3]) << 4 | (pBPCanMsg->Data[2] >> 4)) * 10 + (pBPCanMsg->Data[2] & 0x0F); /*轮径，精度0.1寸*/
        pBikeInfo->MCU.WheelCircumference = ((uint16_t)pBPCanMsg->Data[5] << 8) | pBPCanMsg->Data[4];   /*车轮周长，精度1mm*/
        break;
    }
    case 0x3204:
    {
        pBikeInfo->MCU.PowerOff = pBPCanMsg->Data[0] & 0x01;    /*电控关机信息*/
        break;
    }
    case 0x3205:/*卡路里*/
    {
        pBikeInfo->MCU.Cal = (uint16_t)pBPCanMsg->Data[1] << 8 | pBPCanMsg->Data[0];    /*卡路里，单位：千卡*/
        break;
    }
    case 0x3400:      /*电池信息*/
    {
        pBikeInfo->Battery.TotalCapacity  = ((uint16_t)pBPCanMsg->Data[1] << 8) | pBPCanMsg->Data[0];   /*总容量*/
        pBikeInfo->Battery.RemainCapacity = ((uint16_t)pBPCanMsg->Data[3] << 8) | pBPCanMsg->Data[2];   /*剩余容量*/
        pBikeInfo->Battery.RelChargeState = pBPCanMsg->Data[4];                                         /*相对容量百分比*/
        pBikeInfo->Battery.AbsChargeState = pBPCanMsg->Data[5];                                         /*绝对容量百分比*/
        //pBikeInfo->Battery.SOH            = pBPCanMsg->Data[6];                                         /*SOH*/
        break;
    }
    case 0x3401:
    {
        pBikeInfo->Battery.TotalCurrent = (int16_t)(((int16_t)pBPCanMsg->Data[1] << 8) | pBPCanMsg->Data[0]);   /*总电流，精度0.01A，正为充电，负为放电*/
        pBikeInfo->Battery.TotalVoltage = ((uint16_t)pBPCanMsg->Data[3] << 8) | pBPCanMsg->Data[2];             /*总电压，精度0.01V*/
        pBikeInfo->Battery.Temperature  = pBPCanMsg->Data[4] - 40;                                              /*温度*/
        break;
    }
    case 0x6400:
    {
        pBikeInfo->Battery.SeriesNum   = pBPCanMsg->Data[0];  /*电池串数*/
        pBikeInfo->Battery.ParallelNum = pBPCanMsg->Data[1];  /*电池并数*/
        break;
    }
    default:
    {
        break;
    }
    }
}

/******************************************************************************
** 功  能：发送数据帧
** 参  数：SourceID-源ID，TargetID-目标ID，Cmd-命令字，Index-索引值，SubIndex-子索引,Datalen-数据长度，pData-指向数据区指针
** 返回值：无
** 备  注：
******************************************************************************/
void vBP_CAN_Send_Msg(enuNodeID SourceID,enuNodeID TargetID,enuCommand Cmd,uint8_t Index,uint8_t SubIndex,uint8_t Datalen,uint8_t * pData)
{
    strBP_CAN   lxSendMsg;
    uint8_t n;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Src   = SourceID;
    lxSendMsg.ID_Dst   = TargetID;
    lxSendMsg.Command  = Cmd;
    lxSendMsg.Index    = Index;
    lxSendMsg.SubIndex = SubIndex;
    lxSendMsg.DLC      = Datalen;

    if(pData != NULL)
    {
        for(n = 0; n < Datalen; n++)
        {
            lxSendMsg.Data[n] = * (pData + n);
        }
    }

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/

}

/******************************************************************************
** 功  能：发送正确应答帧
** 参  数：SourceID-源ID，TargetID-目标ID，Index-索引值，SubIndex-子索引,Datalen-数据长度，pData-指向数据区指针
** 返回值：无
** 备  注：
******************************************************************************/
void vBP_CAN_Send_OK_Ack(enuNodeID SourceID,enuNodeID TargetID,uint8_t Index,uint8_t SubIndex,uint8_t Datalen,uint8_t * pData)
{
    strBP_CAN   lxSendMsg;
    uint8_t n;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Src   = SourceID;
    lxSendMsg.ID_Dst   = TargetID;
    lxSendMsg.Command  = Command_Ack_Ok;          /*0x02是正确应答指令*/
    lxSendMsg.Index    = Index;
    lxSendMsg.SubIndex = SubIndex;
    lxSendMsg.DLC      = Datalen;

    if(pData != NULL)
    {
        for(n = 0; n < Datalen; n++)
        {
            lxSendMsg.Data[n] = * (pData + n);
        }
    }

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/

}

/******************************************************************************
** 功  能：发送错误应答帧
** 参  数：SourceID-源ID，TargetID-目标ID，Index-索引值，SubIndex-子索引,Datalen-错误代码长度，pData-指向错误代码指针
** 返回值：无
** 备  注：
******************************************************************************/
void vBP_CAN_Send_Error_Ack(enuNodeID SourceID,enuNodeID TargetID,uint8_t Index,uint8_t SubIndex,uint8_t Datalen,uint8_t * pData)
{
    strBP_CAN   lxSendMsg;
    uint8_t n;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Src   = SourceID;
    lxSendMsg.ID_Dst   = TargetID;
    lxSendMsg.Command  = Command_Ack_Error;          /*0x03是错误应答指令*/
    lxSendMsg.Index    = Index;
    lxSendMsg.SubIndex = SubIndex;
    lxSendMsg.DLC      = Datalen;

    if(pData != NULL)
    {
        for(n = 0; n < Datalen; n++)
        {
            lxSendMsg.Data[n] = * (pData + n);
        }
    }

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/

}


/******************************************************************************
** 功  能：获取MCU硬件版本号
** 参  数：pBuffer-存储版本号的字符数组缓冲区，len-缓冲区长度，最大允许40
** 返回值：版本号字符长度
** 备  注：
******************************************************************************/
uint8_t vPROTOCOL_Get_MCU_HardwareVersion(char * pBuffer,uint16_t len)
{
    uint16_t n = 0;
    while(n < len)
    {
        if(gxBikeInfo.MCU.HardwareVersion[n] > 0)
        {
            *(pBuffer + n) = gxBikeInfo.MCU.HardwareVersion[n];
            n++;
        }
        else
        {
            break;
        }
    }
    return n;
}

/******************************************************************************
** 功  能：获取MCU软件版本号
** 参  数：pBuffer-存储版本号的字符数组缓冲区，len-缓冲区长度，最大允许40
** 返回值：版本号字符长度
** 备  注：
******************************************************************************/
uint8_t vPROTOCOL_Get_MCU_SoftwareVersion(char * pBuffer,uint16_t len)
{
    uint16_t n = 0;
    while(n < len)
    {
        if(gxBikeInfo.MCU.SoftwareVersion[n] > 0)
        {
            *(pBuffer + n) = gxBikeInfo.MCU.SoftwareVersion[n];
            n++;
        }
        else
        {
            break;
        }
    }
    return n;
}

/******************************************************************************
** 功  能：获取传感器硬件版本号
** 参  数：pBuffer-存储版本号的字符数组缓冲区，len-缓冲区长度，最大允许40
** 返回值：版本号字符长度
** 备  注：
******************************************************************************/
uint8_t vPROTOCOL_Get_HubLock_HardwareVersion(char * pBuffer,uint16_t len)
{
    uint16_t n = 0;
    while(n < len)
    {
        if(gxBikeInfo.HubLock.HardwareVersion[n] > 0)
        {
            *(pBuffer + n) = gxBikeInfo.HubLock.HardwareVersion[n];
            n++;
        }
        else
        {
            break;
        }
    }
    return n;
}

/******************************************************************************
** 功  能：获取传感器软件版本号
** 参  数：pBuffer-存储版本号的字符数组缓冲区，len-缓冲区长度，最大允许40
** 返回值：版本号字符长度
** 备  注：
******************************************************************************/
uint8_t vPROTOCOL_Get_HubLock_SoftwareVersion(char * pBuffer,uint16_t len)
{
    uint16_t n = 0;
    while(n < len)
    {
        if(gxBikeInfo.HubLock.SoftwareVersion[n] > 0)
        {
            *(pBuffer + n) = gxBikeInfo.HubLock.SoftwareVersion[n];
            n++;
        }
        else
        {
            break;
        }
    }
    return n;
}

/******************************************************************************
** 功  能：获取电池硬件版本号
** 参  数：pBuffer-存储版本号的字符数组缓冲区，len-缓冲区长度，最大允许40
** 返回值：版本号字符长度
** 备  注：
******************************************************************************/
uint8_t vPROTOCOL_Get_BAT_HardwareVersion(char * pBuffer,uint16_t len)
{
    uint16_t n = 0;
    while(n < len)
    {
        if(gxBikeInfo.Battery.HardwareVersion[n] > 0)
        {
            *(pBuffer + n) = gxBikeInfo.Battery.HardwareVersion[n];
            n++;
        }
        else
        {
            break;
        }
    }
    return n;
}

/******************************************************************************
** 功  能：获取电池软件版本号
** 参  数：pBuffer-存储版本号的字符数组缓冲区，len-缓冲区长度，最大允许40
** 返回值：版本号字符长度
** 备  注：
******************************************************************************/
uint8_t vPROTOCOL_Get_BAT_SoftwareVersion(char * pBuffer,uint16_t len)
{
    uint16_t n = 0;
    while(n < len)
    {
        if(gxBikeInfo.Battery.SoftwareVersion[n] > 0)
        {
            *(pBuffer + n) = gxBikeInfo.Battery.SoftwareVersion[n];
            n++;
        }
        else
        {
            break;
        }
    }
    return n;
}

/******************************************************************************
** 功  能：获取MCU发送的速度信息
** 参  数：无
** 返回值：速度值，单位0.01km/h
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_Speed(void)
{
    return gxBikeInfo.ErrCode == 0x30 ? 0 : gxBikeInfo.MCU.Speed;/*报30错误（通信错误）时，返回速度0*/
}

/******************************************************************************
** 功  能：获取MCU发送的剩余电量信息
** 参  数：无
** 返回值：电量值，单位1%
** 备  注：
******************************************************************************/
int8_t     ucPROTOCOL_Get_MCU_Soc(void)
{
    return gxBikeInfo.MCU.RemainCapacity;
}

/******************************************************************************
** 功  能：获取MCU发送的踏频信息
** 参  数：无
** 返回值：踏频值，单位1rpm
** 备  注：
******************************************************************************/
uint8_t     usPROTOCOL_Get_Cadence(void)
{
    return gxBikeInfo.MCU.Cadence;
}

/******************************************************************************
** 功  能：获取MCU发送的电流信息
** 参  数：无
** 返回值：电流值，单位0.01A
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_Current(void)
{
    return gxBikeInfo.MCU.Current;
}

/******************************************************************************
** 功  能：获取MCU发送的电压信息
** 参  数：无
** 返回值：电流值，单位0.01V
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_Voltage(void)
{
    return gxBikeInfo.MCU.Voltage;
}

/******************************************************************************
** 功  能：获取MCU发送的限速信息
** 参  数：无
** 返回值：限速值，单位0.01km/h
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_SpeedLimit(void)
{
    return gxBikeInfo.MCU.SpeedLimit;
}


/******************************************************************************
** 功  能：获取MCU发送的轮径信息
** 参  数：无
** 返回值：轮径值，单位0.1英寸
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_WheelSize(void)
{
    return gxBikeInfo.MCU.WheelSize;
}

/******************************************************************************
** 功  能：获取MCU发送的车轮周长
** 参  数：无
** 返回值：车轮周长值，单位1mm
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_WheelCircumference(void)
{
    return gxBikeInfo.MCU.WheelCircumference;
}

/******************************************************************************
** 功  能：获取MCU发送的关机指令
** 参  数：无
** 返回值：关机指令，0-关机，1-不关机
** 备  注：
******************************************************************************/
uint8_t     ucPROTOCOL_Get_MCU_PowerOff(void)
{
    return gxBikeInfo.MCU.PowerOff;
}

/******************************************************************************
** 功  能：获取MCU发送的Trip
** 参  数：无
** 返回值：Trip值，单位0.01km
** 备  注：
******************************************************************************/
uint16_t     usPROTOCOL_Get_Trip(void)
{
    return gxBikeInfo.MCU.Trip;
}

/******************************************************************************
** 功  能：获取MCU发送的Range
** 参  数：无
** 返回值：Range值，单位0.01km
** 备  注：
******************************************************************************/
uint16_t     usPROTOCOL_Get_Range(void)
{
    return gxBikeInfo.MCU.Range;
}

/******************************************************************************
** 功  能：获取错误代码
** 参  数：无
** 返回值：错误代码
** 备  注：
******************************************************************************/
uint8_t     ucPROTOCOL_Get_ErrCode(void)
{
    const uint8_t ErrCodeTab[] = {0x04,0x05,0x07,0x08,0x09,0x10,0x11,0x12,0x14,0x15,0x21,0x23,0x25,0x26,0x27,0x30,0x33,0x35,0x36,0x37};
    uint8_t n;

    if(gxBikeInfo.ErrCode != 0)
    {
        return gxBikeInfo.ErrCode;
    }
    else if((gxBikeInfo.MCU.ErrCode != 0) && (gxBikeInfo.MCU.ErrCode != 0x03) && (gxBikeInfo.MCU.ErrCode != 0x06))
    {
        for(n = 0; n < sizeof(ErrCodeTab) / sizeof(uint8_t); n++)
        {
            if(gxBikeInfo.MCU.ErrCode == ErrCodeTab[n])
            {
                break;
            }
        }
        if(n == sizeof(ErrCodeTab) / sizeof(uint8_t))
        {
            return 0;
        }
        else
        {
            return gxBikeInfo.MCU.ErrCode;
        }
    }
//    else if(gxBikeInfo.Battery.ErrCode != 0)
//    {
//        return gxBikeInfo.Battery.ErrCode;
//    }
//    else if(gxBikeInfo.HubLock.ErrCode != 0)
//    {
//        return gxBikeInfo.HubLock.ErrCode;
//    }
    else
    {
        return 0;
    }
}

/******************************************************************************
** 功  能：获取助推状态
** 参  数：无
** 返回值：助推状态，0-未进入助推，1-进入助推
** 备  注：
******************************************************************************/
uint8_t     ucPROTOCOL_Get_MCU_PushState(void)
{
    return gxBikeInfo.MCU.PushState;
}

/******************************************************************************
** 功  能：获取卡路里值
** 参  数：无
** 返回值：卡路里，单位千卡
** 备  注：
******************************************************************************/
uint16_t     usPROTOCOL_Get_Cal(void)
{
    return gxBikeInfo.MCU.Cal;
}

/******************************************************************************
** 功  能：获取电池温度
** 参  数：无
** 返回值：电池温度，单位：1摄氏度
** 备  注：
******************************************************************************/
int8_t		scPROTOCOL_Get_BAT_Temperature(void)
{
    return gxBikeInfo.Battery.Temperature;
}

/******************************************************************************
** 功  能：获取电池组总容量
** 参  数：无
** 返回值：电池组总容量，单位：1mAh
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_BAT_TotalCapacity(void)
{
    return gxBikeInfo.Battery.TotalCapacity;
}

/******************************************************************************
** 功  能：获取电池组剩余容量
** 参  数：无
** 返回值：电池组剩余容量，单位：1mAh
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_BAT_RemainCapacity(void)
{
    return gxBikeInfo.Battery.RemainCapacity;
}

/******************************************************************************
** 功  能：获取电池组电流
** 参  数：无
** 返回值：电池组总电流，正为充电，负为放电，单位：0.01A
** 备  注：
******************************************************************************/
int16_t		ssPROTOCOL_Get_BAT_TotalCurrent(void)
{
    return gxBikeInfo.Battery.TotalCurrent;
}

/******************************************************************************
** 功  能：获取电池组电压
** 参  数：无
** 返回值：电池组总电压，单位：0.01V
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_BAT_TotalVoltage(void)
{
    return gxBikeInfo.Battery.TotalVoltage;
}

/******************************************************************************
** 功  能：获取电池组单个电芯电压
** 参  数：Cell-电芯号，范围：0-31
** 返回值：给定电芯的电压，单位：0.01V
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_BAT_CellVoltage(uint8_t Cell)
{
    if(Cell > 31)
    {
        Cell = 31;
    }
    return gxBikeInfo.Battery.CellVoltage[Cell];
}

/******************************************************************************
** 功  能：获取电池组相对容量百分比
** 参  数：
** 返回值：电池相对容量百分比，单位：1%
** 备  注：
******************************************************************************/
uint8_t     ucPROTOCOL_Get_BAT_RelChargeState(void)
{
    return gxBikeInfo.Battery.RelChargeState;
}

/******************************************************************************
** 功  能：获取电池组绝对容量百分比
** 参  数：
** 返回值：电池绝对容量百分比，单位：1%
** 备  注：
******************************************************************************/
uint8_t     ucPROTOCOL_Get_BAT_AbsChargeState(void)
{
    return gxBikeInfo.Battery.AbsChargeState;
}

/******************************************************************************
** 功  能：获取电池组SOH
** 参  数：
** 返回值：电池SOH，单位：1%
** 备  注：
******************************************************************************/
uint8_t     ucPROTOCOL_Get_BAT_SOH(void)
{
    return gxBikeInfo.Battery.SOH;
}

/******************************************************************************
** 功  能：获取电池组串数
** 参  数：
** 返回值：电池组串数，单位：1
** 备  注：
******************************************************************************/
uint8_t     ucPROTOCOL_Get_BAT_SeriesNum(void)
{
    return gxBikeInfo.Battery.SeriesNum;
}

/******************************************************************************
** 功  能：获取电池组并数
** 参  数：
** 返回值：电池组并数，单位：1
** 备  注：
******************************************************************************/
uint8_t     ucPROTOCOL_Get_BAT_ParallelNum(void)
{
    return gxBikeInfo.Battery.ParallelNum;
}

/******************************************************************************
** 功  能：获取电池组最大未充电时间
** 参  数：
** 返回值：最大未充电时间，单位：1h
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_BAT_MaxUnchargeTime(void)
{
    return gxBikeInfo.Battery.MaxUnchargeTime;
}

/******************************************************************************
** 功  能：获取电池组最近未充电时间
** 参  数：
** 返回值：最近未充电时间，单位：1h
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_BAT_LastUnchargeTime(void)
{
    return gxBikeInfo.Battery.LastUnchargeTime;
}

/******************************************************************************
** 功  能：获取电池组循环次数
** 参  数：
** 返回值：循环次数，单位：1次
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_BAT_CycleTimes(void)
{
    return gxBikeInfo.Battery.CycleTimes;
}


/******************************************************************************
** 功  能：设置挡位
** 参  数：Pas -挡位值,-1表示助推档，0-9表示挡位
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_Pas(int8_t Pas)
{
    const uint8_t PasTab_3[] = {0,12,2,3};
    const uint8_t PasTab_4[] = {0,1,12,21,3};
    const uint8_t PasTab_5[] = {0,11,13,21,23,3};
    const uint8_t PasTab_9[] = {0,1,11,12,13,2,21,22,23,3};
    if(Pas < 0)
    {
        /*Pas小于0表示助推档，向CAN总线发送6*/
        gxBikeInfo.Display.Pas = 6;
    }
    else
    {
        switch(gxBikeInfo.Display.MaxPas)
        {
        case 3:
        {
            gxBikeInfo.Display.Pas = PasTab_3[Pas < gxBikeInfo.Display.MaxPas ? Pas : gxBikeInfo.Display.MaxPas];
            break;
        }
        case 4:
        {
            gxBikeInfo.Display.Pas = PasTab_4[Pas < gxBikeInfo.Display.MaxPas ? Pas : gxBikeInfo.Display.MaxPas];
            break;
        }
        case 5:
        {
            gxBikeInfo.Display.Pas = PasTab_5[Pas < gxBikeInfo.Display.MaxPas ? Pas : gxBikeInfo.Display.MaxPas];
            break;
        }
        case 9:
        {
            gxBikeInfo.Display.Pas = PasTab_9[Pas < gxBikeInfo.Display.MaxPas ? Pas : gxBikeInfo.Display.MaxPas];
            break;
        }
        }
    }
}

/******************************************************************************
** 功  能：设置最大挡位
** 参  数：MaxPas-最大挡位值
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_MaxPas(uint8_t MaxPas)
{
    gxBikeInfo.Display.MaxPas = MaxPas;
}


/******************************************************************************
** 功  能：设置总骑行时间
** 参  数：TotalTime-总骑行时间，单位：分钟
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_TotalTime(uint32_t TotalTime)
{
    gxBikeInfo.Display.TotalTime = TotalTime;
}

/******************************************************************************
** 功  能：设置自动关机时间
** 参  数：IdleTime-自动关机时间，0代表不自动关机，单位：分钟
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_IdleTime(uint8_t    IdleTime)
{
    gxBikeInfo.Display.IdleTime = IdleTime > 0 ? IdleTime : 0xFF;
}

/******************************************************************************
** 功  能：设置ODO值
** 参  数：Odo-Odo里程，单位：km
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_Odo(uint32_t Odo)
{
    gxBikeInfo.Display.Odo = Odo;
}

/******************************************************************************
** 功  能：设置Trip
** 参  数：Trip-Trip值，单位：0.1Km
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_Trip(uint32_t Trip)
{
    gxBikeInfo.Display.Trip = Trip;
}

/******************************************************************************
** 功  能：设置最大速度
** 参  数：MaxSpeed-最大速度，单位：0.1km/h
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_MaxSpeed(uint16_t MaxSpeed)
{
    gxBikeInfo.Display.MaxSpeed = MaxSpeed;
}

/******************************************************************************
** 功  能：设置平均速度
** 参  数：AvgSpeed-平均速度，单位：0.1km/h
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_AvgSpeed(uint16_t AvgSpeed)
{
    gxBikeInfo.Display.AvgSpeed = AvgSpeed;
}

/******************************************************************************
** 功  能：设置剩余保养里程
** 参  数：ServiceMileage-剩余保养里程，单位：0.1km
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_ServiceMileage(uint32_t ServiceMileage)
{
    gxBikeInfo.Display.ServiceMileage = ServiceMileage;
}

/******************************************************************************
** 功  能：设置骑行模式
** 参  数：Mode-骑行模式
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_Mode(uint8_t Mode)
{
    gxBikeInfo.Display.Mode = Mode;
}

/******************************************************************************
** 功  能：设置花鼓锁模式
** 参  数：lock-开/关锁
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_HubLock(uint8_t lock)
{
    gxBikeInfo.Display.HubLock = lock;
}
/******************************************************************************
** 功  能：设置大灯状态
** 参  数：Lamp-大灯状态，0-关闭，1-打开
** 返回值：无
** 备  注：无
******************************************************************************/
void        vPROTOCOL_Set_Lamp(uint8_t Lamp)
{
    gxBikeInfo.Display.LampAndKeyState &= 0xFE;
    gxBikeInfo.Display.LampAndKeyState |= (Lamp & 0x01);
}

/******************************************************************************
** 功  能：清Trip
** 参  数：ClearTrip-清Trip指令，1-不清Trip，0-清Trip
** 返回值：无
** 备  注：ClearTrip被置0后，会自动恢复为1
******************************************************************************/
void        vPROTOCOL_Set_ClearTrip(void)
{
    gxBikeInfo.Display.ClearTrip = 0;
    gucTripCleared = 0;
}

/******************************************************************************
** 功  能：设置UP键状态
** 参  数：KeyState-按键状态，0-释放，1-按下
** 返回值：无
** 备  注：不得传入0、1以外的值
******************************************************************************/
void        vPROTOCOL_Set_UpKeyState(uint8_t KeyState)
{
    gxBikeInfo.Display.LampAndKeyState = (gxBikeInfo.Display.LampAndKeyState & 0xFD) | ((KeyState & 0x01) << 1);
}

/******************************************************************************
** 功  能：设置i键状态
** 参  数：KeyState-按键状态，0-释放，1-按下
** 返回值：无
** 备  注：不得传入0、1以外的值
******************************************************************************/
void        vPROTOCOL_Set_iKeyState(uint8_t KeyState)
{
    gxBikeInfo.Display.LampAndKeyState = (gxBikeInfo.Display.LampAndKeyState & 0xFB) | ((KeyState & 0x01) << 2);
}

/******************************************************************************
** 功  能：设置大灯键状态
** 参  数：KeyState-按键状态，0-释放，1-按下
** 返回值：无
** 备  注：不得传入0、1以外的值
******************************************************************************/
void        vPROTOCOL_Set_LampKeyState(uint8_t KeyState)
{
    gxBikeInfo.Display.LampAndKeyState = (gxBikeInfo.Display.LampAndKeyState & 0xF7) | ((KeyState & 0x01) << 3);
}

/******************************************************************************
** 功  能：仪表发送0x6400的数据报文
** 参  数：DstNodeID-目标节点地址
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_Send_Display_Msg6400(enuNodeID DstNodeId)
{
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Dst   = DstNodeId;      /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Write;  /*命令为写*/
    lxSendMsg.Index    = 0x64;           /*索引*/
    lxSendMsg.SubIndex = 0x00;           /*子索引*/
    lxSendMsg.DLC      = 1;              /*数据长度为1*/
    lxSendMsg.Data[0]  = gxBikeInfo.Display.HubLock;

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}

/******************************************************************************
** 功  能：仪表发送0x6300的数据报文
** 参  数：DstNodeID-目标节点地址
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_Send_Display_Msg6300(enuNodeID DstNodeId)
{
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Dst   = DstNodeId;      /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Write;  /*命令为写*/
    lxSendMsg.Index    = 0x63;           /*索引*/
    lxSendMsg.SubIndex = 0x00;           /*子索引*/
    lxSendMsg.DLC      = 4;              /*数据长度为4*/
    lxSendMsg.Data[0]  = (gxBikeInfo.Display.Mode << 4) | gxBikeInfo.Display.MaxPas;
    lxSendMsg.Data[1]  = gxBikeInfo.Display.Pas;
    lxSendMsg.Data[2]  = gxBikeInfo.Display.LampAndKeyState;
    lxSendMsg.Data[3]  = gxBikeInfo.Display.ClearTrip;

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/
    /*如果要求清Trip，发送清Trip指令后，等待MCU反馈的Trip值为0后，把对应标志位置1，确保只发送一次清Trip指令*/
    if(gxBikeInfo.Display.ClearTrip == 0)
    {
        if(gucTripCleared == 1)
        {
            gxBikeInfo.Display.ClearTrip = 1;
        }
    }
}

/******************************************************************************
** 功  能：仪表发送0x6301的数据报文
** 参  数：DstNodeID-目标节点地址
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_Send_Display_Msg6301(enuNodeID DstNodeId)
{
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Dst   = DstNodeId;      /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Ack_Ok; /*命令为写*/
    lxSendMsg.Index    = 0x63;           /*索引*/
    lxSendMsg.SubIndex = 0x01;           /*子索引*/
    lxSendMsg.DLC      = 8;              /*数据长度为8*/
    lxSendMsg.Data[0]  = gxBikeInfo.Display.Odo & 0x000000FF;
    lxSendMsg.Data[1]  = (gxBikeInfo.Display.Odo >> 8) & 0x000000FF;
    lxSendMsg.Data[2]  = (gxBikeInfo.Display.Odo >> 16) & 0x000000FF;
    lxSendMsg.Data[3]  = gxBikeInfo.Display.Trip & 0x000000FF;
    lxSendMsg.Data[4]  = (gxBikeInfo.Display.Trip >> 8) & 0x000000FF;
    lxSendMsg.Data[5]  = (gxBikeInfo.Display.Trip >> 16) & 0x000000FF;
    lxSendMsg.Data[6]  = gxBikeInfo.Display.MaxSpeed & 0x000000FF;
    lxSendMsg.Data[7]  = (gxBikeInfo.Display.MaxSpeed >> 8) & 0x000000FF;

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/

}

/******************************************************************************
** 功  能：仪表发送0x6302的数据报文
** 参  数：DstNodeID-目标节点地址
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_Send_Display_Msg6302(enuNodeID DstNodeId)
{
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Dst   = DstNodeId;      /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Ack_Ok; /*命令为写*/
    lxSendMsg.Index    = 0x63;           /*索引*/
    lxSendMsg.SubIndex = 0x02;           /*子索引*/
    lxSendMsg.DLC      = 5;              /*数据长度为5*/
    lxSendMsg.Data[0]  = gxBikeInfo.Display.AvgSpeed                & 0x000000FF;
    lxSendMsg.Data[1]  = (gxBikeInfo.Display.AvgSpeed >> 8)         & 0x000000FF;
    lxSendMsg.Data[2]  = gxBikeInfo.Display.ServiceMileage          & 0x000000FF;
    lxSendMsg.Data[3]  = (gxBikeInfo.Display.ServiceMileage >> 8)   & 0x000000FF;
    lxSendMsg.Data[4]  = (gxBikeInfo.Display.ServiceMileage >> 16)  & 0x000000FF;

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/

}

/******************************************************************************
** 功  能：仪表发送0x6303的数据报文
** 参  数：DstNodeID-目标节点地址
** 返回值：无
** 备  注：
******************************************************************************/
static void vBP_CAN_Send_Display_Msg6303(enuNodeID DstNodeId)
{
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Dst   = DstNodeId;      /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Write;  /*命令为写*/
    lxSendMsg.Index    = 0x63;           /*索引*/
    lxSendMsg.SubIndex = 0x03;           /*子索引*/
    lxSendMsg.DLC      = 1;              /*数据长度为1*/
//    if(gxBikeInfo.Display.IsInPassword == 1)
//    {
//        /*如果当前处于密码输入界面，自动关机时间强制按照1分钟设定*/
//        lxSendMsg.Data[0] = 1;
//    }
//    else
    {
        lxSendMsg.Data[0]  = gxBikeInfo.Display.IdleTime;
    }

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/

}

/******************************************************************************
** 功  能：仪表发送0x3000的心跳帧
** 参  数：DstNodeID-目标节点地址
** 返回值：无
** 备  注：10秒一次
******************************************************************************/
static void vBP_CAN_Send_Display_Msg3000(enuNodeID DstNodeId)
{
    static uint32_t lulTicks = 0;
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lulTicks++;

    lxSendMsg.ID_Dst   = DstNodeId;      /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Write;  /*命令为写*/
    lxSendMsg.Index    = 0x30;           /*索引*/
    lxSendMsg.SubIndex = 0x00;           /*子索引*/
    lxSendMsg.DLC      = 4;              /*数据长度为4*/
    lxSendMsg.Data[3]  = lulTicks >> 24;
    lxSendMsg.Data[2]  = lulTicks >> 16;
    lxSendMsg.Data[1]  = lulTicks >> 8;
    lxSendMsg.Data[0]  = lulTicks;

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/

}

/******************************************************************************
** 功  能：发送请求对应节点硬件版本号的命令
** 参  数：DstNodeID-目标节点地址
** 返回值：无
** 备  注：
******************************************************************************/
void vBP_CAN_Send_Get_Hardware_Version(enuNodeID DstNodeId)
{
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Dst   = DstNodeId;      /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Read;   /*命令为读*/
    lxSendMsg.Index    = 0x60;           /*索引*/
    lxSendMsg.SubIndex = 0x00;           /*子索引*/
    lxSendMsg.DLC      = 0;              /*数据长度为0*/

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}

/******************************************************************************
** 功  能：发送请求对应节点软件版本号的命令
** 参  数：DstNodeID-目标节点地址
** 返回值：无
** 备  注：
******************************************************************************/
void vBP_CAN_Send_Get_Software_Version(enuNodeID DstNodeId)
{
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Dst   = DstNodeId;      /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Read;   /*命令为读*/
    lxSendMsg.Index    = 0x60;           /*索引*/
    lxSendMsg.SubIndex = 0x01;           /*子索引*/
    lxSendMsg.DLC      = 0;              /*数据长度为0*/

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}


/******************************************************************************
** 功  能：获取分段读命令的数据
** 参  数：pBPCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Get_LongDataRead(strBP_CAN   *pBPCanMsg,strBikeInfo *pBikeInfo)
{
    static uint8_t state = 0;		/*状态机变量*/
    static uint8_t SourceID = 0,TargetID = 0;
    static uint8_t DataLen = 0;
    static uint8_t SubIndex = 0;
    static uint8_t Index = 0;
    static uint8_t Buffer[24];
    uint8_t n;
    static uint32_t Ticks;
    switch(state)
    {
    case 0:	/*初始状态，等待长数据传输起始帧*/
    {
        if(pBPCanMsg->Index == 0x60 && pBPCanMsg->Command == 0x04)/*长数据读响应的起始帧*/
        {
            SourceID = pBPCanMsg->ID_Src;		/*源设备ID*/
            TargetID = pBPCanMsg->ID_Dst;		/*目标设备ID*/
            DataLen  = pBPCanMsg->Data[0];		/*数据长度*/
            Index    = pBPCanMsg->Index;        /*索引*/
            SubIndex = pBPCanMsg->SubIndex;	    /*子索引*/

            /*发送响应帧*/
            vBP_CAN_Send_OK_Ack((enuNodeID)TargetID,(enuNodeID)SourceID,Index,SubIndex,0,NULL);

            for(n = 0; n < 24; n++)
            {
                Buffer[n] = 0;
            }
            state = 1;		/*转状态，开始接收中间帧*/
            Ticks = ulBsp_Getticks();	/*获取当前时间戳，用于判断帧超时*/

        }
        break;
    }
    case 1: /*接收到从机发来的数据帧*/
    {
        /*接收到中间帧或者结束帧，把有效数据取出放入缓存*/
        if(pBPCanMsg->ID_Src == SourceID && pBPCanMsg->ID_Dst == TargetID && (pBPCanMsg->Command == 0x05 || pBPCanMsg->Command == 0x06))
        {
            for(n = 0; n < pBPCanMsg->DLC; n++)
            {
                Buffer[pBPCanMsg->SubIndex * 8 + n] = pBPCanMsg->Data[n];
            }

            /*发送响应帧*/
            vBP_CAN_Send_OK_Ack((enuNodeID)TargetID,(enuNodeID)SourceID,Index,SubIndex,0,NULL);
            /*如果是结束帧，转状态0，否则状态不变，继续等待中间帧*/
            if(pBPCanMsg->Command == 0x06)
            {
                switch(SourceID)
                {
                case Node_HubLock:	/*传感器版本号*/
                {
                    if(SubIndex == 0x00)
                    {
                        /*硬件版本号*/
                        for(n = 0; n < DataLen; n++)
                        {
                            pBikeInfo->HubLock.HardwareVersion[n] = Buffer[n];	/*将版本号信息拷贝到对应数组*/
                        }
                    }
                    else if(SubIndex == 0x01)
                    {
                        /*软件版本号*/
                        for(n = 0; n < DataLen; n++)
                        {
                            pBikeInfo->HubLock.SoftwareVersion[n] = Buffer[n];	/*将版本号信息拷贝到对应数组*/
                        }
                    }
                    else if(SubIndex == 0x02)
                    {
                        /*型号*/
                    }
                    else if(SubIndex == 0x03)
                    {
                        /*SN*/
                    }
                    break;
                }
                case Node_MCU:	/*控制器版本号*/
                {
                    if(SubIndex == 0x00)
                    {
                        /*硬件版本号*/
                        for(n = 0; n < DataLen; n++)
                        {
                            pBikeInfo->MCU.HardwareVersion[n] = Buffer[n];	/*将版本号信息拷贝到对应数组*/
                        }
                    }
                    else if(SubIndex == 0x01)
                    {
                        /*软件版本号*/
                        for(n = 0; n < DataLen; n++)
                        {
                            pBikeInfo->MCU.SoftwareVersion[n] = Buffer[n];	/*将版本号信息拷贝到对应数组*/
                        }
                    }
                    else if(SubIndex == 0x02)
                    {
                        /*型号*/
                    }
                    else if(SubIndex == 0x03)
                    {
                        /*SN*/
                    }
                    break;
                }
                case Node_Battery:	/*电池版本号*/
                {
                    if(SubIndex == 0x00)
                    {
                        /*硬件版本号*/
                        for(n = 0; n < DataLen; n++)
                        {
                            pBikeInfo->Battery.HardwareVersion[n] = Buffer[n];	/*将版本号信息拷贝到对应数组*/
                        }
                    }
                    else if(SubIndex == 0x01)
                    {
                        /*软件版本号*/
                        for(n = 0; n < DataLen; n++)
                        {
                            pBikeInfo->Battery.SoftwareVersion[n] = Buffer[n];	/*将版本号信息拷贝到对应数组*/
                        }
                    }
                    else if(SubIndex == 0x02)
                    {
                        /*型号*/
                    }
                    else if(SubIndex == 0x05)
                    {
                        /*SN*/
                    }
                    break;
                }
                }
                state = 0;		/*接收完全部的有效数据了，转状态0*/
            }
            Ticks = ulBsp_Getticks();	/*更新帧间超时时间戳*/
        }
        else
        {
            if(ulBsp_Getticks() - Ticks > 200)
            {
                state = 0;	/*起始帧发送后，200ms内没有接收到中间帧，认为是超时，返回状态0*/
            }
        }

        break;
    }

    }
}

/******************************************************************************
** 功  能：向电池系统发送请求电池信息的一组命令
** 参  数：无
** 返回值：无
** 备  注：包括0x6400，0x6401，0x6402-0x6409
******************************************************************************/
void vBP_CAN_Send_Get_Battery_Info(uint8_t SubIndex)
{
    strBP_CAN   lxSendMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxSendMsg.ID_Dst   = Node_Battery;   /*目标节点ID*/
    lxSendMsg.ID_Src   = Node_LCD;       /*源节点ID为仪表*/
    lxSendMsg.Command  = Command_Read;   /*命令为读*/
    lxSendMsg.DLC      = 0;              /*数据长度为0*/
    lxSendMsg.Index    = 0x64;           /*索引*/
    lxSendMsg.SubIndex = SubIndex;       /*子索引*/

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxSendMsg,sizeof(strBP_CAN),&lxState); /*将数据放入发送队列，排队发送*/

}

/******************************************************************************
** 功  能：向电池系统发送请求电池软硬件版本号命令
** 参  数：无
** 返回值：无
** 备  注：该函数需要定时调用，目前是放在CAN_Loop循环中进行循环调用。周期20ms。读两个
**        版本号之间的时间间隔是400ms
******************************************************************************/
void vBP_CAN_Send_Get_All_Version(void)
{
    static uint8_t lucState = 0;/*状态标志*/
    static uint8_t lucCnt = 0;
    switch(lucState)
    {
    case 0:
    {
        if(++lucCnt > 400 / CAN_LOOP_CYCLE)
        {
            /*判断当前要读的版本号是否已经获取到，没有获取到，重新发送读取命令，已获取到，转下一个状态*/
            if(gxBikeInfo.MCU.HardwareVersion[0] == 0)
            {
                vBP_CAN_Send_Get_Hardware_Version(Node_MCU);
                lucCnt = 0;
            }
            else
            {
                lucState = 1;
            }

        }

        break;
    }
    case 1:
    {
        if(++lucCnt > 400 / CAN_LOOP_CYCLE)
        {
            /*判断当前要读的版本号是否已经获取到，没有获取到，重新发送读取命令，已获取到，转下一个状态*/
            if(gxBikeInfo.MCU.SoftwareVersion[0] == 0)
            {
                vBP_CAN_Send_Get_Software_Version(Node_MCU);
                lucCnt = 0;
            }
            else
            {
                lucState = 2;
            }

        }
        break;
    }
    case 2:
    {
        if(++lucCnt > 400 / CAN_LOOP_CYCLE)
        {
            /*判断当前要读的版本号是否已经获取到，没有获取到，重新发送读取命令，已获取到，转下一个状态*/
            if(gxBikeInfo.Battery.HardwareVersion[0] == 0)
            {
                vBP_CAN_Send_Get_Hardware_Version(Node_Battery);
                lucCnt = 0;
            }
            else
            {
                lucState = 3;
            }

        }
        break;
    }
    case 3:
    {
        if(++lucCnt > 400 / CAN_LOOP_CYCLE)
        {
            /*判断当前要读的版本号是否已经获取到，没有获取到，重新发送读取命令，已获取到，转下一个状态*/
            if(gxBikeInfo.Battery.SoftwareVersion[0] == 0)
            {
                vBP_CAN_Send_Get_Software_Version(Node_Battery);
                lucCnt = 0;
            }
            else
            {
                lucState = 4;
            }

        }
        break;
    }
    default:
    {
        break;
    }
    }
}

/******************************************************************************
** 功  能：复位通信超时计数变量
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_ResetCommunicationOverTime(void)
{
    lulCommunicationCnt = 0;
}

/******************************************************************************
** 功  能：设置当前处于密码输入模式
** 参  数：IsInPassword-是否处于密码输入模式，0-正常模式，1-密码输入模式
** 返回值：无
** 备  注：在密码输入模式，仪表只发送心跳帧和自动关机时间帧
******************************************************************************/
void vPROTOCOL_Set_InPassword(uint8_t IsInPassword)
{
    gxBikeInfo.Display.IsInPassword = IsInPassword;
}

/******************************************************************************
** 功  能：设置按键状态
** 参  数：KeyValue-按键键值
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Button(uint8_t KeyValue)
{
    if((KeyValue & KEY_VALUE_1) == KEY_VALUE_1)
    {
        vPROTOCOL_Set_UpKeyState(1);
    }
    else
    {
        vPROTOCOL_Set_UpKeyState(0);
    }
    if((KeyValue & KEY_VALUE_2) == KEY_VALUE_2)
    {
        vPROTOCOL_Set_iKeyState(1);
    }
    else
    {
        vPROTOCOL_Set_iKeyState(0);
    }
    if((KeyValue & KEY_VALUE_5) == KEY_VALUE_5)
    {
        vPROTOCOL_Set_LampKeyState(1);
    }
    else
    {
        vPROTOCOL_Set_LampKeyState(0);
    }
}

/******************************************************************************
** 功  能：开机上电时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_PowerOn(void)
{
    vPROTOCOL_Set_MaxPas(gtParam.Pas_Max);
    vPROTOCOL_Set_HubLock(gtParam.Hublock);
    vPROTOCOL_Set_Mode(gtParam.Mode);
    vPROTOCOL_Set_IdleTime(gtParam.Idle_Time);
    vPROTOCOL_Set_AvgSpeed(gtRiding.Speed_Avg);
    vPROTOCOL_Set_MaxSpeed(gtRiding.Speed_Max);
    vPROTOCOL_Set_Trip(gtRiding.Trip / 10);
    vPROTOCOL_Set_Odo(gtRiding.ODO / 100);
    vPROTOCOL_Set_ServiceMileage(gtRiding.Service_Milage);
    vPROTOCOL_Set_Pas(0);
    vPROTOCOL_Set_ClearTrip();

}

/******************************************************************************
** 功  能：开机上电时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_ExitSetting(void)
{
    vPROTOCOL_Set_MaxPas(gtParam.Pas_Max);
    vPROTOCOL_Set_HubLock(gtParam.Hublock);
    vPROTOCOL_Set_IdleTime(gtParam.Idle_Time);
    vPROTOCOL_Set_Mode(gtParam.Mode);
    vPROTOCOL_Set_Pas(gcPas);

}


void vSet_And_Save_ODO(uint32_t ODO)                                      /*设置ODO里程，并保存*/
{
}
void vSet_And_Save_TRIP(uint32_t Trip)                                    /*设置Trip里程，并保存*/
{
}

void vSet_Clock(uint8_t Hour,uint8_t Min,uint8_t Sec)                     /*设置时间*/
{
}
void vSet_And_Save_ServiceMileage(uint32_t Mileage)                       /*设置服务里程*/
{
}
void vSave_ErrorCode(uint8_t ErrorCode)                                   /*保存错误代码*/
{
}

